/*
Copyright (C) 2003  Pierrick Brihaye
pierrick.brihaye@wanadoo.fr

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
or connect to:
http://www.fsf.org/copyleft/gpl.html
*/

package gpl.pierrick.brihaye.aramorph.lucene;

import gpl.pierrick.brihaye.aramorph.AraMorph;
import gpl.pierrick.brihaye.aramorph.Solution;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Logger;

import org.apache.lucene.analysis.TokenFilter;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.TermAttribute;

/** A stemmer that will return the possible stems for arabic tokens.*/
public class ArabicStemmerReplicator extends TokenFilter {
	private static final Logger logger = Logger.getLogger(ArabicStemmer.class.getName());
	private AraMorph araMorph;
	private boolean processingToken = false;	
	private ArrayList<Solution> tokenSolutions = null;
	
	private TermAttribute termAtt;
	private PositionIncrementAttribute posIncrAtt;
	private GlossAttribute glossAtt;
	private POSAttribute posAtt;

	/** Constructs a stemmer that will return the possible stems for arabic tokens in the Buckwalter transliteration system.
	 * @param input The token stream from a tokenizer
	 */
	public ArabicStemmerReplicator(TokenStream input) {
		this(input, AraMorph.getNormalizedJDBC());
	}
	
	/** Constructs a stemmer that will return the possible stems for arabic tokens.
	 * @param input The reader
	 * @param debug Whether or not the stemmer should display convenience messages on <CODE>System.out</CODE>
	 * @param outputBuckwalter Whether or not the analyzer should output tokens in the Buckwalter transliteration system
	 */
	public ArabicStemmerReplicator(TokenStream input, AraMorph araMorph) {
		super(input);
		this.araMorph = araMorph;
		termAtt = (TermAttribute) addAttribute(TermAttribute.class);
		posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class);
		glossAtt = (GlossAttribute) addAttribute(GlossAttribute.class);
		posAtt = (POSAttribute) addAttribute(POSAttribute.class);
	}	
	
	/** Returns the Arabic stemmer in use.
	 * @return The Arabic stemmer
	 * @see gpl.pierrick.brihaye.aramorph.AraMorph
	 */
	public AraMorph getAramorph() { return araMorph; }
	
	/** Returns the next stem for the given token.
	 * @param firstOne Whether or not this stem is the first one
	 * @return The token. Its <CODE>termText</CODE> is arabic <STRONG>stem</STRONG>. Its <CODE>type</CODE> is the grammatical category of the <STRONG>stem</STRONG>.
	 * When several stems are available, every emitted token's
	 * <CODE>PositionIncrement</CODE> but the first one is set to <CODE>0</CODE>
	 * @see org.apache.lucene.analysis.Token#setPositionIncrement(int)
	 */
	private void nextSolution(boolean firstOne) {
		//Get the first solution
		Solution currentSolution = tokenSolutions.get(0);
		//This is the trick ! Only the canonical form of the stem is to be considered
		String tokenText = currentSolution.getStemVocalization(false);
		if (tokenText == null)
			tokenText = "";
		termAtt.setTermBuffer(tokenText);
		//Token is typed in order to filter it later			
		String tokenType = currentSolution.getStemPOS(false, false);
		if (tokenType == null)
			tokenType = "NO_STEM";
		posAtt.setPOS(tokenType);
		//OK : we're done with this solution
		tokenSolutions.remove(0);
		//Will there be further treatment ?
		processingToken = !tokenSolutions.isEmpty();
		logger.info(termAtt.term() + "\t" + posAtt.getPOS() + "\t" + posIncrAtt.getPositionIncrement());
	}
	
	/** Returns the next token in the stream, or <CODE>null</CODE> at EOS.
	 * @throws IOException If a problem occurs
	 * @return The token with its <CODE>type</CODE> set to the morphological identification of the
	 * <STRONG>stem</STRONG>. Tokens with no grammatical identification have their <CODE>type</CODE> set to
	 * <CODE>NO_RESULT</CODE>. Token's termText is the romanized form of the
	 * <STRONG>stem</STRONG>
	 * @see org.apache.lucene.analysis.Token#type()
	 */
	@Override
	public boolean incrementToken() throws IOException {
		//If no token is currently processed, fetch another one
		if (!processingToken) {
			if (!input.incrementToken())
				return false;
			//Analyze it (in Arabic)
			Iterator<Solution> wordSolutions = araMorph.getWordSolutions(termAtt.term());
			if (wordSolutions != null) {
				tokenSolutions = new ArrayList<Solution>();
				while (wordSolutions.hasNext())
					tokenSolutions.add(wordSolutions.next());
				processingToken = true;
				return true;
			}
			processingToken = false;
			glossAtt.setGloss("no result");
			posAtt.setPOS("no result");
			return true;
		}
		posIncrAtt.setPositionIncrement(0);
		nextSolution(false);
		return true;
	}
	
	public static void main(String[] args) {
		try {
			String arabicText = "من كان حالفا";
			ArabicTokenizer at = new ArabicTokenizer(new StringReader(arabicText));
			ArabicStemmerReplicator asr = new ArabicStemmerReplicator(at);
			while (asr.incrementToken()) {
//				System.out.print(asr.getAttribute(PositionIncrementAttribute.class).getPositionIncrement());
//				System.out.print(':');
//				System.out.println(asr.getAttribute(TermAttribute.class).term());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


